package org.streets.eis.ext.rbac.pages;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.wicket.Component;
import org.apache.wicket.Page;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow.PageCreator;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.FormComponent;
import org.apache.wicket.markup.html.link.AbstractLink;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.util.string.Strings;
import org.streets.commons.util.GUID;
import org.streets.database.ExecMode;
import org.streets.database.Limits;
import org.streets.database.SQLBatcher;
import org.streets.database.SQLConnection;
import org.streets.eis.component.dropdown.ToolBar;
import org.streets.eis.component.grid.ColumnType;
import org.streets.eis.component.grid.DateTimeColumn;
import org.streets.eis.component.grid.DefualtNavigatorLabel;
import org.streets.eis.component.grid.EditFlagColumn;
import org.streets.eis.component.grid.EditableColumn;
import org.streets.eis.component.grid.TableList;
import org.streets.eis.component.grid.TableList.ExcelFile;
import org.streets.eis.component.messagebox.MessageBox;
import org.streets.eis.component.messagebox.MessageBox.ReturnType;
import org.streets.eis.component.model.DataModel;
import org.streets.eis.component.model.DefaultTableModel;
import org.streets.eis.component.model.MenuItem;
import org.streets.eis.entity.Organization;
import org.streets.eis.entity.Position;
import org.streets.eis.entity.Role;
import org.streets.eis.pages.BasePage;
import org.streets.eis.setting.validatior.TableListValidator;
import org.streets.eis.types.UnitType;

import com.inmethod.grid.IGridColumn;
import com.inmethod.grid.column.CheckBoxColumn;
import com.inmethod.grid.column.PropertyColumn;

public class PositionListPage extends BasePage {
	@Inject
	private SQLConnection conn;
	
	private TableList<Position> posList;
	
	private TableList<Role> roleList;
	
	private ModalWindow childWindow;
	
	private String positionSql = "SELECT * FROM EIS_POSITION WHERE ORGAN_ID='%s' "; 
	
	private String roleSql = "SELECT * FROM EIS_ROLES WHERE ORGAN_ID='%s' ";
	
	private String sql;
	
	private String organId;
	
	private FeedbackPanel feedbackPanel; 
	
	@SuppressWarnings("unchecked")
	public PositionListPage(final String organId){
		super();
		
		positionSql = String.format(positionSql,organId);
		roleSql = String.format(roleSql,organId);
		this.organId = organId;
		
		add(new Label("htmlTitle","职位列表"));
		
		add(childWindow = new ModalWindow("childWindow"));
		childWindow.setOutputMarkupId(true);
		
		feedbackPanel = new FeedbackPanel("feedback");	
		
		Form form = new Form("form"){
			private static final long serialVersionUID = 1L;
			protected void onError(){
				posList.onValidateError(feedbackPanel);
			}
		};
		
		add(form);
		
		form.add(feedbackPanel.setOutputMarkupId(true));
		form.add(posList=createPositionList("posList"));
		posList.setAllowSelectMultiple(false);	
		posList.setClickRowToSelect(true);
		posList.setShowFilterBar(true);		

		form.add(roleList=createRoleList("roleList"));

		roleList.setAllowSelectMultiple(true);	
		roleList.setClickRowToSelect(true);
		roleList.setClickRowToDeselect(true);
		
		form.add(roleList);
		
		form.add(createToolBar());
    }
	
	private ToolBar createToolBar(){
		DataModel<MenuItem> model = new DataModel<MenuItem>();
		model.addChild(new DataModel<MenuItem>(new MenuItem("insert","insert","新增职位")));
		model.addChild(new DataModel<MenuItem>(new MenuItem("copy","copy","从上级公司复制职位")));
		model.addChild(new DataModel<MenuItem>(new MenuItem("post","post","保存修改")));
		model.addChild(new DataModel<MenuItem>(new MenuItem("refresh","refresh","&nbsp;刷新&nbsp;")));
		model.addChild(new DataModel<MenuItem>(new MenuItem("delete","delete","&nbsp;删除&nbsp;")));
		model.addChild(new DataModel<MenuItem>(new MenuItem("saveAs","saveAs","导出职位列表")));
		
		return new ToolBar("toolbar",model){
			private static final long serialVersionUID = 1L;
			@Override
			protected boolean needFormSubmitted(MenuItem menuItem){
				return "post".equals(menuItem.getCode());
			}
			@Override
			protected void onMenuItemClicked(AbstractLink link,DataModel<MenuItem> dataModel,AjaxRequestTarget target){
				if ("insert".equals(dataModel.getObject().getCode())){
        			insert(target);
        		}
				if ("copy".equals(dataModel.getObject().getCode())){
        			copyPosition(target);
        		}
				if ("delete".equals(dataModel.getObject().getCode())){
        			deleteSelected(target);
        		}
				if ("post".equals(dataModel.getObject().getCode())){
        			postIt(target);
        		}
				if ("refresh".equals(dataModel.getObject().getCode())){
					posList.cancelEditAllRows();
					posList.resetSelectedItems();
					roleList.resetSelectedItems();
					target.addComponent(getPage());
        		}
				if ("saveAs".equals(dataModel.getObject().getCode())){
					saveAsExcel(target);
        		}				
        	}
        };
	}

	private TableList<Position> createPositionList(String id){
		return new TableList<Position>(id, new DefaultTableModel<Position>(){
			private static final long serialVersionUID = 1L;
			@Override
			public List<Position> getPageRecords(long offset,int limit,String sortProperty,boolean isAsc){
				String orderBy = (!Strings.isEmpty(sortProperty)) ? " ORDER BY " + sortProperty +(isAsc? " ASC" : " DESC") : "";
				StringBuffer where = new StringBuffer(" and (1=1 ");
				for (String filterSql : posList.getFilterSqls().values()){
					where.append(" and ").append(filterSql);
				}
				where.append(")");
				sql = positionSql + where.toString() + orderBy;
				return conn.query(sql , Position.class,Limits.none());
			}
			@Override
			protected  long getRecordsCount(){
				return conn.count(sql);
			}
		}, generatePositionColumns()){
			private static final long serialVersionUID = 1L;
			@Override
			protected Position reloadRowObject(final Position curValue){
				return conn.unique(positionSql + " AND ID=?",Position.class,new String[]{curValue.getId()});
			}
			@Override
			protected Component newNavigationLabel(String id) {
				return new DefualtNavigatorLabel(id,this);
			}
			@Override
			protected Component newPagingNavigator(String id) {
				return new WebMarkupContainer(id);
			}
			@SuppressWarnings("unchecked")
			@Override
			public void onItemSelectionChanged(IModel item, boolean newValue) {
				super.onItemSelectionChanged(item, newValue);
				roleList.resetSelectedItems();
				if (newValue){					
					if (posList.getSelectedItems().size()==1){
						Position pos = (Position) item.getObject();
						for (IModel<Role> roleModel : roleList.getRowModels()){
							if (pos.getRoles().contains(roleModel.getObject())){
								roleList.selectItem(roleModel, true);
							}
						}
					}
				}
				roleList.update();				
			}
		}.add(new TableListValidator<Position>("unique.position.name","name") {
			private static final long serialVersionUID = 1L;
			@Override
			public boolean doValidate(FormComponent<?>[] formComponents,Position object) {
				return conn.count("SELECT * FROM EIS_POSITION WHERE NAME=? AND ORGAN_ID=? AND ID<>?",new Object[]{formComponents[0].getInput(),organId,object.getId()}) == 0;
			}
			@Override
			public boolean doValidate(	Map<Position, FormComponent<?>[]> editedRows) {
				List<String> tmp = new ArrayList<String>(editedRows.size());
				for (FormComponent<?>[] formComponents : editedRows.values()){
					String key = formComponents[0].getInput();
					if (tmp.contains(key)){
						return false;
					} else {
						tmp.add(key);
					}
				}
				return true;
			}
		});
	}
	
	private TableList<Role> createRoleList(String id){
		return new TableList<Role>(id, new DefaultTableModel<Role>(){
			private static final long serialVersionUID = 1L;
			@Override
			public List<Role> getPageRecords(long offset,int limit,String sortProperty,boolean isAsc){
				String orderBy = (!Strings.isEmpty(sortProperty)) ? " ORDER BY " + sortProperty +(isAsc? " ASC" : " DESC") : "";
				return conn.query(roleSql + orderBy , Role.class,Limits.none());
			}
			@Override
			protected  long getRecordsCount(){
				return conn.count(roleSql);
			}
		}, generateRoleColumns()){
			private static final long serialVersionUID = 1L;
			@Override
			protected Component newNavigationLabel(String id) {
				return new DefualtNavigatorLabel(id,this);
			}
			@Override
			protected Component newPagingNavigator(String id) {
				return new WebMarkupContainer(id);
			}
		};
	}
	
	private List<IGridColumn> generatePositionColumns(){
		List<IGridColumn> columns = new ArrayList<IGridColumn>();
		columns.add(new CheckBoxColumn("check"));
		columns.add(new EditFlagColumn("editFlag"));
		columns.add(new EditableColumn(Model.of("职位名称"), "name", "NAME") {
			private static final long serialVersionUID = 1L;
			
			@SuppressWarnings("unchecked")
			@Override
			protected void addValidators(FormComponent component) {
				component.setRequired(true);
			}
		});
		
		columns.add(new DateTimeColumn(Model.of("有效截止日期"), "validTo","VALID_TO",ColumnType.DateTime.DATE){
			private static final long serialVersionUID = 1L;

			@SuppressWarnings("unchecked")
			@Override
			protected void addValidators(FormComponent component) {
				component.setRequired(true);
			}
		}.setInitialSize(100));
		
		return columns;
	}

	private List<IGridColumn> generateRoleColumns(){
		List<IGridColumn> columns = new ArrayList<IGridColumn>();
		columns.add(new CheckBoxColumn("check"));
		columns.add(new PropertyColumn(Model.of("角色标识"), "code", "CODE"));
		columns.add(new PropertyColumn(Model.of("角色名称"), "name", "NAME"));
		columns.add(new PropertyColumn(Model.of("角色值"), "value", "VALUE"));
		
		return columns;
	}
	
	private void insert(AjaxRequestTarget target){
		childWindow.setPageCreator(new PageCreator(){
			private static final long serialVersionUID = 1L;
			public Page createPage() {
				return new PositionInsertPage(childWindow,organId);
			}			
		});
		childWindow.setTitle("新增职位");
		childWindow.setWindowClosedCallback(new ModalWindow.WindowClosedCallback(){
			private static final long serialVersionUID = 1L;
			public void onClose(AjaxRequestTarget target){
				target.addComponent(getPage());
			}
		});

		childWindow.setMinimalWidth(500);
		childWindow.setMinimalHeight(400);
		childWindow.setInitialWidth(500);
		childWindow.setInitialHeight(400);		
		childWindow.show(target);
	}
	
	private void copyPosition(AjaxRequestTarget target){
		Organization org = conn.unique(Organization.class, organId);
		if (conn.count(String.format("SELECT * FROM EIS_POSITION WHERE ORGAN_ID='%s'",org.getId()))>0){
			getMessageBox().warning("此机构下已经存在职位。不能从上级公司再复制职位！");
			return;
		}
		Organization tmp = org;
		while((tmp=conn.unique(Organization.class, tmp.getParentId()))!=null){
			if (tmp.getAttr().equals(String.valueOf(UnitType.GROUP.value()))||
					tmp.getAttr().equals(String.valueOf(UnitType.COMPANY.value()))){
				String sourceSql = String.format("SELECT * FROM EIS_POSITION WHERE ORGAN_ID='%s'",tmp.getId());
				List<Position> source = conn.query(sourceSql , Position.class, Limits.none());
				
				if (source.size()>0){					
					String destSql = "INSERT INTO EIS_POSITION(ID,NAME,VALID_TO,ORGAN_ID) VALUES(?,?,?,?)";
					SQLBatcher batcher = conn.prepare(destSql);	
					for(Position pos : source){
						batcher.add(new Object[]{
								GUID.nextUUID(),
								pos.getName(),
								pos.getValidTo(),
								organId
						});
					}
					batcher.execute();
					getMessageBox().alert("从"+tmp.getName()+"成功复制了"+source.size()+"条职位记录！",new MessageBox.DialogCallback(){
						private static final long serialVersionUID = 1L;

						public void onDialogClosed(AjaxRequestTarget target,ReturnType result) {
							target.addComponent(getPage());
						}
					});
					return;
				}
			}
		}
		getMessageBox().error("所有上级公司均没有职位信息。无法完成复制！");
	}
	
	@SuppressWarnings("unchecked")
	private void deleteSelected(AjaxRequestTarget target){
		if (posList.getSelectedItems().size()>0){
			getMessageBox().question("确定要删除"+posList.getSelectedItems().size()+"条记录吗？",new MessageBox.DialogCallback(){
				private static final long serialVersionUID = 1L;

				public void onDialogClosed(AjaxRequestTarget target,	ReturnType result) {
					if (result == ReturnType.YES){						
						StringBuffer sqls = new StringBuffer();
						for (Iterator iterator = posList.getSelectedItems().iterator(); iterator.hasNext();) {
							IModel rowModel = (IModel) iterator.next();
							//删除前一定要先将所选行设为未选
							posList.selectItem(rowModel,false);
							Position t = (Position) (rowModel).getObject();
							sqls.append(String.format(
									"UPDATE EIS_EMPLOYEE SET POS_ID=null WHERE POS_ID='%s';"+
									"DELETE FROM EIS_POS_ROLE_MAP WHERE POS_ID='%s';"+
									"DELETE FROM EIS_POSITION WHERE ID='%s';",
									t.getId(),t.getId(),t.getId()));
						}
						conn.execute(sqls.toString());
						target.addComponent(getPage());
					}
				}
				
			});			
		} else {
			getMessageBox().error("请选择要删除的记录!");
		}
	}
	
	private void postIt(AjaxRequestTarget target){
		List<IModel<Position>> editedList = posList.getEditingRowModels();		
		if (editedList.size()>0){
			for (Iterator<IModel<Position>> iterator = editedList.iterator(); iterator.hasNext();) {
				IModel<Position> rowModel = iterator.next();
				conn.execute(rowModel.getObject(), ExecMode.UPDATE);
				posList.setItemEdit(rowModel, false);
			}
			target.addComponent(feedbackPanel);
			posList.update();
		}
		
		List<Position> selected = posList.getSelectedRowModelObjects();
		if (selected.size()==1){
			Position editedPosition = selected.get(0);
			String posId = editedPosition.getId();
			
			conn.execute(String.format("DELETE FROM EIS_POS_ROLE_MAP WHERE POS_ID='%s';",posId));
			
			String relationSql = "INSERT INTO EIS_POS_ROLE_MAP(ID,POS_ID,ROLE_ID,STATUS) VALUES(?,?,?,?)";
			SQLBatcher batcher = conn.prepare(relationSql);
			editedPosition.getRoles().clear();
			editedPosition.getRoles().addAll(roleList.getSelectedRowModelObjects());
			for (Role role : editedPosition.getRoles()){
				batcher.add(new String[]{
						GUID.nextUUID(),
						posId,
						role.getId(),
						"1" //FIXME：status取值范围
				});
			}
			batcher.execute();
			
		} else {
			if (editedList.size()==0){
				getMessageBox().warning("不能同时修改多个职位的对应角色!");
			}
		}
	}	
	
	private void saveAsExcel(AjaxRequestTarget target){
		posList.setCreateExcelCallback(new TableList.CreateExcelFileCallback(){
			private static final long serialVersionUID = 1L;
			public ExcelFile createExcel() {
				String fileName = String.format("职位列表-%s.xls",new SimpleDateFormat("yyyyMMdd").format(new Date()));
				return posList.generateExcelFile(fileName,"职位列表",conn.query(sql , Position.class,Limits.none()),posList.getAllColumns());
			}
		});	
		target.appendJavascript(posList.getSaveAsExcelJavascript());
	}	
}
